Skip to content

ci: close four release-integrity gaps - #537

Merged
thcp merged 1 commit into
0.16.1from
fix/517-release-integrity
Aug 31, 2026
Merged

ci: close four release-integrity gaps#537
thcp merged 1 commit into
0.16.1from
fix/517-release-integrity

Conversation

@thcp

@thcp thcp commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes #517. Independent; branches off 0.16.1.

1. Deno pinned and checksummed

build/Dockerfile:38 fetched from releases/latest/download/ with no version pin and no checksum, into every published GHCR image. Deno is the JS runtime yt-dlp feeds YouTube's challenge payload to, so it executes against untrusted input.

The project's own standard already covers this -- make-runtime-pack.sh:186-194 pins QuickJS by asset and SHA256 and verifies with shasum -c, with the rationale written out in a comment. Docker was the one path that did not follow it.

Now pinned to v2.9.6 with a per-arch SHA256, verified before unpacking:

x86_64-unknown-linux-gnu   394f07f4da2bebe6ce6f1e7ce0fa16429b29b08c35e3fac3fe25972676dff4b2
aarch64-unknown-linux-gnu  9a46afc6c392c7cd2ff71a31558935545b46408d0e87f7a86908c712721c046e

Both verified against the published artifacts, including a negative control confirming a wrong hash is rejected by the exact sha256sum -c form the Dockerfile uses.

2. Releases can no longer publish an incomplete asset set

action-gh-release defaults fail_on_unmatched_files to false, and neither Linux nor Windows asserted its files existed first -- macOS has 8 test -f checks, those two had none.

A missing updater asset therefore published a release that went green while the in-app updater 404'd for every installed user.

Both workflows now verify every asset before uploading, and set fail_on_unmatched_files: true as a second line.

3. PowerShell failures are no longer ignored

make-portable.ps1:12 set $PSNativeCommandErrorActionPreference, which exists only in PowerShell 7+. CI invokes the script with powershell -- Windows PowerShell 5.1 -- where it does nothing, and $ErrorActionPreference does not cover native commands either.

A failed CPU-torch --force-reinstall was ignored, leaving whatever torch was already resolved in place, so the zip labelled CPU shipped a non-CPU torch. The later import checks still passed, because torch imports fine either way.

Assert-LastExitCode now guards the venv creation and all three pip installs.

Why not just switch to pwsh: that was the tidier fix, but nothing in this repo uses pwsh and the runner is self-hosted, so there is no way for me to confirm PowerShell 7 is installed there. Switching could break the release outright. An exit-code check works on both versions.

4. trivy-action pinned

ci.yml:181,193 used @master -- the only unpinned action in the repo, while everything else is SHA-pinned. Now on v0.36.0's commit ed142fd.

Verification

yaml.safe_load   ci.yml, linux-release.yml, windows-release.yml all parse
deno hashes      both verified, plus a negative control

Two things I could not verify locally, worth noting:

  • PowerShell syntax is unchecked. pwsh is not installed on this machine, so make-portable.ps1 was edited without a parser pass. The changes are a function definition and four call sites, but a second pair of eyes on that file would be worth having.
  • The Dockerfile was not built. The Docker daemon is not running here. The Deno logic was verified by running the identical curl/sha256sum -c sequence outside a container, but the layer itself has not been exercised.

Deno was fetched from releases/latest/download with no version pin and no
checksum, into every published GHCR image. It is the JS runtime yt-dlp feeds
YouTube's challenge payload to, so it executes against untrusted input, and
every build took whatever Deno published that day. The desktop packaging
scripts already pin and verify QuickJS with the rationale written out in a
comment -- Docker was the one path that did not follow it. Now pinned to
v2.9.6 with a per-arch SHA256 verified before the zip is unpacked.

linux-release.yml and windows-release.yml uploaded with
action-gh-release, whose fail_on_unmatched_files defaults to false, and
neither asserted the files existed first -- macOS is the only path that did.
A missing updater asset therefore published a release that went green while
the in-app updater 404'd for every installed user. Both now check every asset
before uploading and set fail_on_unmatched_files.

make-portable.ps1 set $PSNativeCommandErrorActionPreference, which exists only
in PowerShell 7+, while CI invokes it with `powershell` -- Windows PowerShell
5.1, where it does nothing and $ErrorActionPreference does not cover native
commands either. A failed CPU-torch --force-reinstall was ignored, leaving
whatever torch was already resolved in place, and the zip labelled CPU shipped
a non-CPU torch; the later import checks still passed because torch imports
fine either way. Assert-LastExitCode now guards the venv creation and all
three pip installs. The preference stays for a pwsh run.

Switching the invocation to pwsh would have been the tidier fix, but nothing
in this repo uses pwsh and the runner is self-hosted, so there is no way to
confirm PowerShell 7 is installed there. An exit-code check works on both.

trivy-action was pinned to @master, the only unpinned action in the repo while
everything else is SHA-pinned. Now on v0.36.0's commit.

Both Deno hashes were verified against the published artifacts, including a
negative control confirming a wrong hash is rejected.

Refs #517
@thcp
thcp marked this pull request as ready for review August 31, 2026 21:18
@thcp
thcp merged commit 2835c8f into 0.16.1 Aug 31, 2026
8 checks passed
@thcp
thcp deleted the fix/517-release-integrity branch September 3, 2026 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant